import os
import datetime
from django.shortcuts import render, redirect
from app_article.models import Article, UpOrDown, Comment, Category, Tags
from app_blog.models import Blog
from django.db.models import Sum
from lib.CommonResponse import CommonResponse
from django.contrib.auth.decorators import login_required
from django.views import View
from bs4 import BeautifulSoup
from django.conf import settings


def article_detail(request, username, pk):
    _pk_list_all = Article.objects.filter(blog__userinfo__username=username).values('pk').all()
    _pk_list = [d1.get('pk') for d1 in _pk_list_all]
    if pk in _pk_list:
        # 如果文章在id列表中执行以下代码
        # 获得当前文章的id在所有id列表中索引位置
        index = _pk_list.index(pk)
        if index == 0:
            # index =0 表示显示的是当前用户的第一篇文章
            index = 1
        elif index == len(_pk_list) - 1:
            # 如果索引 = 总长度减1 也就意味着显示的是最后一篇文章
            # 将索引-1 用来展示最后一篇文章
            index -= 1
        # 显示上一篇和下一篇文章
        last_article_obj = Article.objects.get(pk=_pk_list[index - 1])
        if len(_pk_list) == 1:
            # 如果总共只有一篇文章，那么下一篇还是第一篇
            next_article_obj = Article.objects.get(pk=_pk_list[index - 1])
        else:
            next_article_obj = Article.objects.get(pk=_pk_list[index + 1])
    article_now = Article.objects.get(pk=pk)
    # blog_obj为了保留样式
    blog_obj = Blog.objects.get(userinfo__username=username)
    # 文章总数
    article_data_all = Article.objects.filter(blog=blog_obj)
    # 点赞总数
    up_gross = article_data_all.aggregate(up_gross=Sum('up_count'))['up_gross']
    # 点踩总数
    down_gross = article_data_all.aggregate(down_gross=Sum('down_count'))['down_gross']
    # 评论总数
    comment_gross = article_data_all.aggregate(comment_gross=Sum('comment_count'))['comment_gross']
    return render(request, 'article_detail.html', locals())


@login_required
def edit_article_like(request):
    if request.is_ajax() and request.method == 'POST':
        user_obj = request.user
        if not user_obj.is_authenticated:
            return CommonResponse(code=400, errors='请先登录')
        # 获取ajax发送的数据
        data = request.POST
        article_id = int(data.get('article_id'))
        is_up = True if data.get('tag') == 'true' else False
        state = '点赞' if is_up else '点踩'

        article_obj = Article.objects.get(pk=article_id)  # 文章对象
        up_down_obj = UpOrDown.objects.filter(user=user_obj, article=article_obj).first()  # 点赞或点踩对象
        if article_obj.blog.userinfo.username == user_obj.username:
            return CommonResponse(code=402, errors='不能给自己点赞或点踩！')
        # 进行条件判断
        if up_down_obj:
            # 原表中有则进行是否一致判断
            if up_down_obj.is_up == is_up:
                # 一致返回不可重复提交
                return CommonResponse(code=403, errors=f'当前用户已{state}，不可重复{state}')
            else:
                # 不一致进行更新
                up_down_obj.is_up = is_up
                up_down_obj.save()
                if is_up:
                    article_obj.up_count += 1
                    article_obj.down_count -= 1
                else:
                    article_obj.up_count -= 1
                    article_obj.down_count += 1
        else:
            # 如果原表中没有值，新增值
            UpOrDown.objects.create(user=user_obj, article=article_obj, is_up=is_up)
            if is_up:
                article_obj.up_count += 1
            else:
                article_obj.down_count += 1
        # 更新文章对象的修改操作
        article_obj.save()
        return CommonResponse(code=200, msg=f'{state}成功')


@login_required
def add_comment(request):
    if request.is_ajax() and request.method == 'POST':
        data = request.POST
        article_id = data.get('article_id')
        article_obj = Article.objects.get(pk=article_id)
        content = data.get('content')
        parent_id = data.get('parent_id')
        user_obj = request.user
        Comment.objects.create(article=article_obj, content=content, user=user_obj, parent_id=parent_id)
        article_obj.comment_count += 1
        article_obj.save()
        return CommonResponse(code=200, msg='评论成功！')


class AnalysisContentMixin():
    @staticmethod
    def __analysis_content(content):
        # 解析HTML
        soup = BeautifulSoup(content, 'lxml')
        desc = soup.text[:50]
        # 找到js标签防止xss攻击
        original_paragraph = soup.script

        # 直接删除script标签块 或 使用下面的替换
        # original_paragraph.replace_with('')

        if not original_paragraph:
            # 如果文章中没有写js代码就可以直接返回
            return desc, content
        # 创建一个新的段落
        new_paragraph = soup.new_tag("p")
        new_paragraph.string = str(soup.script)

        # 用新的段落替换原始段落
        original_paragraph.replace_with(new_paragraph)
        content = soup.prettify()

        return desc, content

    def get_request_data(self, data):
        title = data.get('title')
        create_time = data.get('create_time')
        if not create_time:
            create_time = datetime.datetime.now()
        category_id = data.get('category')
        content = data.get('content')
        desc, content = self.__analysis_content(content)
        return title, desc, create_time, category_id, content


class AddArticle(View, AnalysisContentMixin):
    def get(self, request, username):
        blog_obj = Blog.objects.get(userinfo=request.user)
        # 统计每个分类
        category_all = Category.objects.filter(blog=blog_obj)
        # 统计每个标签
        tags_all = Tags.objects.filter(blog=blog_obj)
        return render(request, 'article_add.html', locals())

    def post(self, request, username):
        data = request.POST
        blog_obj = Blog.objects.get(userinfo=request.user)
        title, desc, create_time, category_id, content = self.get_request_data(data)
        tags = data.getlist('tags')
        article_obj = Article.objects.create(title=title, desc=desc,
                                             create_time=create_time, category_id=category_id,
                                             blog=blog_obj, content=content)
        article_obj.tags.set(tags)
        article_obj.save()
        return CommonResponse(code=200, msg=f'【{title}】添加成功')


def delArticle(request, pk, username):
    article_obj = Article.objects.get(pk=pk)
    article_obj.is_delete = True
    article_obj.save()
    return redirect('backend:backend')


class EditArticle(View, AnalysisContentMixin):
    def get(self, request, username, pk):
        article_obj = Article.objects.get(pk=pk)
        blog_obj = Blog.objects.get(userinfo=request.user)
        # 统计每个分类
        category_all = Category.objects.filter(blog=blog_obj)
        # 统计每个标签
        tags_all = Tags.objects.filter(blog=blog_obj)
        return render(request, 'article_edit.html', locals())

    def post(self, request, username, pk):
        data = request.POST
        title, desc, create_time, category_id, content = self.get_request_data(data)
        tags = data.getlist('tags')
        article_obj = Article.objects.filter(pk=pk)
        article_obj.update(title=title, desc=desc, create_time=create_time,
                           category_id=category_id, content=content)
        article_obj.first().tags.set(tags)
        article_obj.first().save()
        return CommonResponse(code=200, msg=f'【{title}】修改成功')


def articleImg(request):
    file_obj = request.FILES.get('imgFile')
    # 设置保存到的文件指定位置
    img_folder_path = os.path.join(settings.BASE_DIR, 'media', 'article_img')
    # 确保文件夹存在
    os.makedirs(img_folder_path, exist_ok=True)
    # 拼接图片存放路径
    img_path = os.path.join(img_folder_path, file_obj.name)
    try:
        # 将图片保存至指定路径 # 一般是media文件夹，保证网页可以通过url获取图片
        with open(img_path, 'wb') as fp:
            for i in file_obj.chunks():
                fp.write(i)
        # 拼接并返回图片url
        url = f'/media/article_img/{file_obj.name}/'
        # 返回的参数格式有讲究的
        # 需要是json格式  # 参数0代表上传成功，参数1代表失败
        # 成功返回url  # 失败返回message  # 参数名称必须是指定的两个
        return CommonResponse(error=0, url=url)
    except Exception as e:
        message = f'发生了一些意外{e}'
        return CommonResponse(error=1, message=message)
